package com.hyacinth.dubbo.io.netty.protocol;

import com.hyacinth.dubbo.io.netty.serialize.Serializer;
import com.hyacinth.dubbo.io.netty.util.ClassUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 编解码器
 * @author zhangfb
 * @version 1.0.0.1
 * @since JDK 1.8
 */
@Slf4j
public class PacketCodec {
    public static final int MAGIC_NUMBER = 0x12345678;
    // 创建单实例
    public static final PacketCodec INSTANCE = new PacketCodec();

    private static Map<Byte, Class<? extends Packet>> packetTypeMap;
    private static Map<Byte, Serializer> serializerMap;

    static {
        // 初始化所有的数据包
        packetTypeMap = new HashMap<>();
        initPacket();

        // 初始序列化工具类
        serializerMap = new HashMap<>();
        initSerializer();
    }

    /**
     * 初始化数据传输包
     */
    private static void initPacket() {
        packetTypeMap.clear();
        // 加载子类
        Set<Class<? extends Packet>> classes = ClassUtil.loadSubClass(Packet.class);
        for (Class<? extends Packet> clz : classes){
            try {
                Packet pack = clz.newInstance();
                packetTypeMap.put(pack.getCommand(), clz);
            } catch (InstantiationException | IllegalAccessException e) {
                log.error("初始化数据传输包出错",e);
            }
        }
    }

    /**
     * 初始序列化工具类
     */
    private static void initSerializer() {
        serializerMap.clear();
        // 加载子类
        Set<Class<? extends Serializer>> classes = ClassUtil.loadSubClass(Serializer.class);
        for (Class<? extends Serializer> clz : classes){
            try {
                Serializer serializer = clz.newInstance();
                serializerMap.put(serializer.getSerializerAlgorithm(), serializer);
            } catch (InstantiationException | IllegalAccessException e) {
                log.error("初始序列化工具类出错",e);
            }
        }
    }

    public void encode(Packet packet, ByteBuf byteBuf) {
        // 1. 序列化 java 对象
        byte[] bytes = Serializer.DEFAULT.serialize(packet);
        // 2. 实际编码过程
        byteBuf.writeInt(MAGIC_NUMBER);
        byteBuf.writeByte(packet.getVersion());
        byteBuf.writeByte(Serializer.DEFAULT.getSerializerAlgorithm());
        byteBuf.writeByte(packet.getCommand());
        byteBuf.writeInt(bytes.length);
        byteBuf.writeBytes(bytes);
    }

    @Deprecated
    public ByteBuf encode(ByteBufAllocator byteBufAllocator, Packet packet) {
        // 1. 创建 ByteBuf 对象
        ByteBuf byteBuf = byteBufAllocator.ioBuffer();
        // 2. 序列化 java 对象
        byte[] bytes = Serializer.DEFAULT.serialize(packet);
        // 3. 实际编码过程
        byteBuf.writeInt(MAGIC_NUMBER);
        byteBuf.writeByte(packet.getVersion());
        byteBuf.writeByte(Serializer.DEFAULT.getSerializerAlgorithm());
        byteBuf.writeByte(packet.getCommand());
        byteBuf.writeInt(bytes.length);
        byteBuf.writeBytes(bytes);
        return byteBuf;
    }


    public Packet decode(ByteBuf byteBuf) {
        // 跳过 magic number
        byteBuf.skipBytes(4);
        // 跳过版本号
        byteBuf.skipBytes(1);
        // 序列化算法
        byte serializeAlgorithm = byteBuf.readByte();
        // 指令
        byte command = byteBuf.readByte();
        // 数据包长度
        int length = byteBuf.readInt();
        byte[] bytes = new byte[length];
        byteBuf.readBytes(bytes);
        Class<? extends Packet> requestType = getRequestType(command);
        Serializer serializer = getSerializer(serializeAlgorithm);
        if (requestType != null && serializer != null) {
            return serializer.deserialize(requestType, bytes);
        }
        return null;
    }

    private Serializer getSerializer(byte serializeAlgorithm) {
        return serializerMap.get(serializeAlgorithm);
    }

    private Class<? extends Packet> getRequestType(byte command) {
        return packetTypeMap.get(command);
    }
}
